/**
##############################################################################
#
# Copyright (C) 2020 Bonainfo <guoyihot@outlook.com>
# All Rights Reserved
#
##############################################################################
 */
odoo.define('iant_dynamic_list_form.DynamicList', function(require) {
    "use strict";

    var BasicView = require('web.BasicView');
    var BasicController = require('web.BasicController');
    var BasicModel = require('web.BasicModel');
    var DynamicModel = require('iant_dynamic_list_form.DynamicListModel');
    var field_registry = require('web.field_registry');
    var framework = require('web.framework');
    var excludeFields = ['id', 'create_date', 'create_uid', 'write_date','write_uid', '__last_update', 'display_name'];

    BasicController.include({
    	init:function(parent, model, renderer, params){
    		this._super.apply(this,arguments);
    		this.actionId = params.actionId;
    		parent = this.getParent();
    		this.on('get_env',this,this._onGetEnv.bind(parent));
    		this.on('config_change',this,this._onConfigChange.bind(parent));
    		this.on('config_save',this,this._onConfigSave.bind(parent));
    		this.on('delete_config',this,this._onConfigDelete.bind(parent));
    	},

    	_onConfigDelete:function(ev){
    		ev.stopPropagation();
    		var self = this;
    		var configModel = this.configModel;
    		var fieldConfigId = configModel.fieldConfigId;
    		var listConfigId = configModel.listConfigId;
    		var prom = [];
    		if(fieldConfigId){
    			var fieldConfig = configModel.get(fieldConfigId);
    			var fieldConfigIds = _.pluck(fieldConfig.data,'id');
    			var deleteConfigIds = _.filter(fieldConfigIds,function(id){return !configModel.isNew(id)});
    			var removeConfigIds = _.filter(fieldConfigIds,function(id){return configModel.isNew(id)});
    			if(_.size(deleteConfigIds)){
    				prom.push(configModel.deleteRecords(deleteConfigIds,'field.config'));
    			}
    			if(_.size(removeConfigIds)){
    				_.each(removeConfigIds,function(id){
    					configModel.removeLine(id);
    					delete configModel.localData[id]
    				});
    			}
    			
    		}
    		if(listConfigId){
    			var listConfig = configModel.get(listConfigId);
    			var listConfigIds = _.pluck(listConfig.data,'id');
    			var deleteListConfigIds = _.filter(listConfigIds,function(id){return !configModel.isNew(id)});
    			var removeListConfigIds = _.filter(listConfigIds,function(id){return configModel.isNew(id)});
    			if(_.size(deleteListConfigIds)){
    				prom.push(configModel.deleteRecords(deleteListConfigIds,'list.config'));
    			}
    			if(_.size(removeListConfigIds)){
    				_.each(removeListConfigIds,function(id){
    					configModel.removeLine(id);
    					delete configModel.localData[id]
    				});
    			}
    		}
    		framework.blockUI();
    		return Promise.all(prom).then(function(){
    			location.reload();
			});
    	},

    	_onConfigSave:function(ev){
    		ev.stopPropagation();
    		var configModel = this.configModel;
    		var fieldConfigId = configModel.fieldConfigId;
    		var listConfigId = configModel.listConfigId;
    		var prom = [];
    		var self = this;
    		if(fieldConfigId){
    			var fieldConfig = configModel.get(fieldConfigId);
    			_.each(fieldConfig.data,function(config){
    				if(excludeFields.indexOf(config.data.name) === -1){
    					prom.push(configModel.save(config.id,{reload: false}));
					}
    			});

    		}
    		if(listConfigId){
    			var listConfig = configModel.get(listConfigId);
    			_.each(listConfig.data,function(config){
    				prom.push(configModel.save(config.id,{reload:false}));
    			});
    		}
    		framework.blockUI();
    		return Promise.all(prom).then(function(){
    			location.reload();
			});
    	},

    	_onGetEnv:function(ev){
    		ev.stopPropagation();
    		if(ev.data.onSuccess){
    			var configModel = this.configModel;
    			ev.data.onSuccess({
					actionId: configModel._action_id,
					viewId: configModel._view_id,
					model: configModel
    			});
    		}
    	},

    	_onConfigChange:function(ev){
    		ev.stopPropagation();
    		var data = ev.data;
    		  if(data.id && data.changes && this.configModel){
    			  this.configModel.notifyChanges(data.id, data.changes);
    		  }
    	  }
    });

    BasicModel.include({
    	init:function(parent,params){
    		this._super.apply(this,arguments);
    		this._action_id = params?params.action_id:-1;
    		this._view_id = params?params.view_id:-1;
    	},

    	// _makeDataPoint: function (params) {
    	// 	var dataPoint = this._super(...arguments);
    	// 	//apply limit config
			// var parent = this.getParent();
    	// 	if(dataPoint.type=="list" && parent.configModel){
    	// 		var formField = '';
    	// 		if(dataPoint.parentID && dataPoint.relationField){
    	// 			var parentRecord = this.localData[dataPoint.parentID];
    	// 			for(var field in parentRecord.fields){
    	// 				var fieldValue = parentRecord.fields[field];
    	// 				if(fieldValue.relation_field && fieldValue.relation_field == dataPoint.relationField){
    	// 					formField = field;
    	// 					break;
    	// 				}
    	// 			}
    	// 		}
    	// 		var limit=dataPoint.limit;
    	// 		var self = this;
    			// Object.defineProperty(dataPoint, 'limit', {
    			// 	  get:function(){
    			// 		  return parent.configModel._getListLimit(formField,this.model);
    			// 	  },
    			// 	  set:function(value){
    			// 		  limit = value;
    			// 	  }
    			//
    			// 	});
    	// 	}
    	//
    	// 	return dataPoint;
    	// },

    	_getFieldNames: function (element, options) {
		 	var names = this._super.apply(this,arguments);
		 	if(!this.configModel){
		 		return names;
		 	}
		 	if(_.contains(['field.config','list.config'],element.model)){
		 		return names;
		 	}
		 	var fieldName = '';
		 	if(element.parentID){
		 		var parentRecord = this.localData[element.parentID];
		 		if(parentRecord && parentRecord.type=='record'){
		 			_.each(parentRecord.data,function(value,key){
		 				if(element.id==value){
		 					fieldName = key;
		 				}
		 			});
		 		}
		 	}
		 	var fieldNamesConfig = this.configModel._getFieldNamesByConfig(fieldName,element.model);
		 	if(_.size(fieldNamesConfig)){
		 		return _.uniq(names.concat(fieldNamesConfig));
		 	}	      
	        return names;
	    },

	    _addX2ManyDefaultRecord: function (list, options) {
	    	if(list){
	    		if(!_.size(list._changes)){
	    			list._changes = [];
	    		}
	    	}
	    	return this._super.apply(this,arguments);
	    },

	    _addConfigFieldInfo:function(id,fieldName){
	    	var self =this;
	    	var list = this.get(id);
	    	if(list.type!='list' || !self.configModel){
	    		return ;
	    	}
	    	var configNames = self.configModel._getFieldNamesByConfig(fieldName,list.model);
        	if(_.size(configNames)){
        		var viewType = list.viewType;
        		var viewInfo = {viewType:viewType,fields:{},fieldInfo:{}};
        		var fieldsInfo={};
        		var fields={};
        		var fieldKeys = _.keys(list.fieldsInfo[viewType]);
        		_.each(configNames,function(name){
        			if(!_.contains(fieldKeys,name)){
        				var field = list.fields[name] ;
        				fieldsInfo[name]={
        						name:name,
        						type:field.type,
        						options:{},
        						Widget:field_registry.get(field.type)
        				}
        			}
        		});
        		viewInfo.fieldInfo=fieldsInfo;
        		self.addFieldsInfo(list.id,viewInfo);
        	}
	    },
	  
	    _reload: function (id, options) {
	    	var self = this;
	    	return this._super.apply(this,arguments).then(function(id){
	    		self._addConfigFieldInfo(id,'');
	    		return id;
	    	})
	    },
	    __load: function (params) {
	    	var self = this;
	    	return this._super.apply(this,arguments).then(function(id){
	    		self._addConfigFieldInfo(id,'');
	    		return id;
	    	});
	    },
	  
    	_fetchX2Manys: function (record, options) {
    	       var self = this;
    	       var fieldNames = options.fieldNames || record.getFieldNames(options);
    	       var viewType = options.viewType || record.viewType;
    	       var x2ManyFields = _.filter(fieldNames,function(name){
    	    	   var field = record.fields[name];
    	    	   var fieldInfo = record.fieldsInfo[viewType][name];
    	    	   return (field.type == 'one2many' || field.type == "many2many") && !fieldInfo.__no_fetch;
    	       });

    	       return this._super.apply(this,arguments).then(function(){
    	    	   _.each(x2ManyFields,function(field){
    	    		   self._addConfigFieldInfo(record.data[field],field);
    	    	   })
    	       });
    	    },

    });
 
    BasicView.include({
    	init:function(viewInfo,params){
    		this._super.apply(this,arguments);
    		this.view_id = viewInfo.view_id;
    		this.modelParams = {};
    		if(params.action){
    			this.modelParams.action_id = params.action.id;
    			this.modelParams.view_id = viewInfo.view_id;
    			this.controllerParams.actionId = params.action.id;
    			this.action_id = params.action.id;
    		}
    	},

    	_loadData:function(model){
            if(this.arch.tag != 'form' && this.arch.tag !='tree'){
    			return this._super(...arguments);
            }
       		let self = this;
       		let _super = this._super.bind(this);
       		let params = {
       				action_id:this.action_id,
       				view_id:this.view_id
       		};
       		var configModel = new DynamicModel(model.getParent(), params);
       		model.configModel = configModel;
       		var proms = [configModel.loadFieldConfig(),configModel.loadListConfig()];
       		return $.when(proms).then(function () {
				return _super(model);
            });
       	},

        getController: function (parent) {

        	return this._super(...arguments).then(function(controller){
        		if(controller.model.configModel){
        			controller.configModel = controller.model.configModel;
        			controller.configModel.setParent(controller);
        		}
        		return controller;
        	});
        },

    	_processFieldsView: function (fieldsView, viewType) {
    		var fv = this._super(...arguments);
    		var self = this;
			viewType = viewType || this.viewType;
			if (viewType === 'list'){
				var fieldsInfoKeys = fv.fieldsInfo[viewType]
				_.each(fieldsView.viewFields, function (fieldinfo, field) {
					if(!_.has(fieldsInfoKeys, field)) {
						fv.fieldsInfo[viewType][field] = self._processField(viewType, field, {modifiers:{invisible:false}})
					}
				})
			}
			return fv;
		},
    	
    });


});
